﻿using Dommel;
using K9Nano.Domain;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;

namespace K9Nano.DapperExtensions
{
    public class DapperReadOnlyRepository<TEntity, TKey> : IReadOnlyRepository<TEntity, TKey>
        where TEntity : class, IEntity<TKey>
        where TKey : IEquatable<TKey>
    {
        protected readonly IReadOnlyDbConnectionFactory ReadOnlyDbConnectionFactory;

        public IDbConnection DbConnection => ReadOnlyDbConnectionFactory.ReadOnlyDbConnection;

        public DapperReadOnlyRepository(IReadOnlyDbConnectionFactory readOnlyDbConnectionFactory)
        {
            this.ReadOnlyDbConnectionFactory = readOnlyDbConnectionFactory;
        }

        public virtual TEntity Get(TKey id)
        {
           return DbConnection.Get<TEntity>(id);
        }

        public virtual async ValueTask<TEntity> GetAsync(TKey id, CancellationToken cancellation = default)
        {
            return await DbConnection.GetAsync<TEntity>(id);
        }

        public virtual List<TEntity> GetAllList()
        {
            return DbConnection.GetAll<TEntity>().ToList();
        }

        public virtual async ValueTask<List<TEntity>> GetAllListAsync(CancellationToken cancellation = default)
        {
            return (await DbConnection.GetAllAsync<TEntity>()).ToList();
        }
        
        public virtual TEntity FirstOrDefault(TKey id)
        {
            return DbConnection.FirstOrDefault<TEntity>(x => x.Id.Equals(id));
        }

        public virtual async ValueTask<TEntity> FirstOrDefaultAsync(TKey id, CancellationToken cancellation = default)
        {
            return await DbConnection.FirstOrDefaultAsync<TEntity>(x => x.Id.Equals(id));
        }

        public virtual TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate)
        {
            return DbConnection.FirstOrDefault<TEntity>(predicate);
        }

        public virtual async ValueTask<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellation = default)
        {
            return await DbConnection.FirstOrDefaultAsync<TEntity>(predicate);
        }
    }
}